
#include "tcpserver.h"
#include "logger.h"
#include "acceptor.h"
#include <memory>
#include<string.h>
#include "inet_address.h"
#include "tcpconnection.h"

EventLoop* checkLoopNotNull(EventLoop* loop){
    if(loop == nullptr){
        LOG_FATAL("%s:%s:%d mainLoop is null! \n", __FILE__, __FUNCTION__, __LINE__);
    }
    return loop;
}

TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr,
        const std::string& nameArg, Option option )
: loop_(checkLoopNotNull(loop))
, ipPort_(listenAddr.toIpPort())
, name_(nameArg)
// acceptor_ 是在EventLoopThreadPool 里面的baseLoop里面执行
, acceptor_(new Acceptor(loop_, listenAddr, option==kReuserPort))
, threadPool_(new EventLoopThreadPool(loop_, nameArg))
, connectionCallBack_()
, messageCallBack_()
, nextConnId_(1)
, started_(0)
{
    // 
  acceptor_->setNewConnectionCallBack(std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));

}

void TcpServer::setThreadNum(int numThreads){
    threadPool_->setThreadNum(numThreads);
}

void TcpServer::start(){
    if(started_ ++ == 0){
        threadPool_->start(threadInitCallBack_);
        loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_.get()));
    }
}

// 有一个新的客户端 的连接， acceptor会执行这个回调操作
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr){
    // 轮询算法 选择一个subLoop， 来管理chanel_
    EventLoop* ioLoop = threadPool_->getNextLoop();
    char buf[64] = {0};
    snprintf(buf, sizeof(buf), "-%s#%d", ipPort_.c_str(), nextConnId_);
    ++ nextConnId_;
    std::string connName = name_ + buf;
    LOG_INFO("TcpServer::newConnection [%s] - new connection [%s] from %s \n",name_.c_str(), connName.c_str(), peerAddr.toIpPort().c_str());
     // 通过sockfd 获取其绑定的本机的ip地址与端口信息
    sockaddr_in localAddr;
    ::bzero(&localAddr, sizeof(localAddr));
    socklen_t addrlen = sizeof(localAddr);
    if(::getsockname(sockfd, (sockaddr*)& localAddr, &addrlen) < 0){
        LOG_ERROR("sockets::getLocalAddr");
    }

    InetAddress local(localAddr);
    TcpConnectionPtr conn(new TcpConnection(
        ioLoop,
        connName,
        sockfd,
        local,
        peerAddr
    ));
    
    connections_[connName] = conn;
    // 下面的回调都是用户设置给TcpServer => TcpConnection  => Channel => Poller => notify
    conn->setConnectionCallBack(connectionCallBack_);
    conn->setMessageCallBack(messageCallBack_);
    conn->setWriteCompleteCallBack(writeCompleteCallBack_);
    conn->setCloseCallBack(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));

    ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn));

}
void TcpServer::removeConnection(const TcpConnectionPtr &conn){
    loop_->runInLoop(std::bind(
        &TcpServer::removeConnectionInLoop, this, conn
    ));
}
void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn){
    size_t n = connections_.erase(conn->name());
    EventLoop* ioLoop = conn->getLoop();
    ioLoop->queueInLoop(
        std::bind(&TcpConnection::connectDestoryed, conn)
    );
}

TcpServer::~TcpServer(){
    for(auto& item : connections_){
        TcpConnectionPtr conn(item.second);
        item.second.reset();

        conn->getLoop()->runInLoop(
             std::bind(&TcpConnection::connectDestoryed, conn)
        );
    }
}